/*************************************
Copyright 2011 Chinua Iloabachie, Pradnya Khutafale, Siyi Liu, Junichi Suzuki, and The University of Massachusetts, Boston (http://code.google.com/p/tabletuml/)


Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 
*************************************/


package touchMe.Draw;
import android.graphics.DashPathEffect;
 

import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.lang.StringEscapeUtils;

import touchMe.Util.DiagramManager;
import touchMe.baseClass.Constants;
import touchMe.baseClass.Diagram;
import touchMe.baseClass.Element;
import touchMe.baseClass.ElementType;
import touchMe.baseClass.RelElement;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Paint.Style;
import android.graphics.Typeface;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.graphics.drawable.shapes.RectShape;
import android.util.Log;
import android.view.View;

public class DrawClass extends View {
	private ShapeDrawable mDrawable;
	private Diagram umlDiagram;
	float x, y, tox, toy;
	Paint p= new Paint();
	Paint p2= new Paint();
	int type;
	// Used for drawing arrow
	PointF a1;
	PointF a2;
	
	public DrawClass(Context context) {
		super(context);
		p.setAntiAlias(true);
		p2.setAntiAlias(true);
		p.setColor(Color.BLACK);
	}
	public DrawClass(Context context,float x, float y, float tox,float toy,int type) {
		super(context);
		this.x=x;
		this.y=y;
		this.tox=tox;
		this.toy=toy;
		p.setAntiAlias(true);
		p.setColor(Color.BLACK);
		p2.setAntiAlias(true);
		this.type=type;
	}	
	
	@Override
	protected void onDraw(Canvas canvas) {
		canvas.drawColor(Color.LTGRAY) ;
		/*if(type==2)// if relation
		{
			
		 canvas.drawLine(x, y, tox, toy, p);
		}*/
		// the code below will be executed while drawing association
		if(type== Constants.INHERITANCE_RELATIONMODE)
		{
			//if inheritance association
			drawInheritanceAssociation(canvas,p,Constants.ADDELEMENT,null,Constants.INHERITANCE_RELATIONMODE);
		}
		if(type== Constants.IMPLEMENTATION_RELATIONMODE)
		{
			//if inheritance association
			drawInheritanceAssociation(canvas,p,Constants.ADDELEMENT,null,Constants.IMPLEMENTATION_RELATIONMODE);
		}
		
		if(type==Constants.RELATIONMODE)
			
		{
			//if inheritance association
			drawInheritanceAssociation(canvas,p,Constants.ADDELEMENT,null,Constants.RELATIONMODE);
		}
			
		umlDiagram=DiagramManager.getUmlDiagram();
		// this portion will load existing associations
		
		for (Element entity : umlDiagram.getElements()) {
			if (entity != null) {
				entity.getType();
				if (entity.getType() == ElementType.CLASS) {
					drawClassDiagram(canvas,entity);
				 }
				if(entity.getType()== ElementType.USECASE)
				{
					drawUseCase(canvas, entity);
				}
				if(entity.getType()==ElementType.ACTOR){
					drawActor(canvas,entity,umlDiagram.getZoomLevel());
				}
				if(entity.getType()==ElementType.SIMPLE_ASSOC)
				{
					
					drawInheritanceAssociation(canvas,p,Constants.LOADELEMENT,entity,Constants.RELATIONMODE);	
				}
				if(entity.getType()==ElementType.INHERITANCE)
				{	
				  // lt=<<-< is UMLet syntax for Inheritance
					drawInheritanceAssociation(canvas,p,Constants.LOADELEMENT,entity,Constants.INHERITANCE_RELATIONMODE);						
				}
				if(entity.getType()==ElementType.IMPLEMENTATION)
				{	
				  // lt=<<-< is UMLet syntax for Inheritance
					drawInheritanceAssociation(canvas,p,Constants.LOADELEMENT,entity,Constants.IMPLEMENTATION_RELATIONMODE);						
				}
		   }
		}
	}
	
	//This logic is taken up from UmLet - com.umLet.element.base.Relation
	// paintEntity Method and some other methods
	public void drawInheritanceAssociation(Canvas canvas,Paint p, int drawMode,Element relElement,int type)
	{
		float x1Float;
		float y1Float;
		float x2Float;
		float y2Float;
		int[] ax = new int[3];
		int[] ay = new int[3];
		p.setColor(Color.BLACK);
		 
		
	 // drawMode - element should be created or load the relation element
		
	    if(drawMode==Constants.ADDELEMENT)
		{
	    	StringBuffer  add_attr= new StringBuffer();
	    	RelElement relationElement = null;
	    	// x, y in element are component origin & w, h are width & hieght of component	
	    	int beginX,beginY,endX,endY;
	    	
	    	if(x<tox && y<=toy){
	    		beginX=(int)x;beginY=(int)y;
	    		add_attr.append((int)0+";"+(int)0+";"+(int)Math.abs(x-tox)+";"+(int)Math.abs(y-toy));
	    		}
	    		//endX=(int)Math.abs(beginX-tox); endY=(int)Math.abs(beginY-toy);}
	    	else if(x>tox && y<=toy){
	    	 beginX=(int)tox;beginY=(int)y;
	    	 add_attr.append((int)Math.abs(beginX-x)+";"+(int)0+";"
	    			 +(int)0+";"+(int)Math.abs(beginY-toy));
	    	 }
	    	 else if(x > tox && y>toy)	{
	    	  beginX = (int)tox; beginY=(int)toy;
	    	  add_attr.append((int)Math.abs(beginX-x)+";"+(int)Math.abs(beginY-toy)+";"
	    			  +(int)0+";"+(int)0);
	    	  }
	    	  else // x < x2(tox) && y1 (y) >=y2 (toy 
	    	  { beginX= (int)x; beginY=(int)toy;
	    	  add_attr.append((int)0+";"+(int)Math.abs(beginY-y)+";"
	    			  +(int)Math.abs(beginX-tox)+";"+(int)0);
	    	  } 
	    	
	    	if(type==Constants.INHERITANCE_RELATIONMODE)
	    	{   	 	
			   relationElement= new RelElement(beginX,beginY,Math.abs(tox+x-10),toy+y-10,ElementType.INHERITANCE);
			    StringBuffer  panelStr= new StringBuffer(Constants.inheritPanelAttr.trim());
			    relationElement.setPanelAttributes(panelStr);
	    	   }
	    	else if(type==Constants.IMPLEMENTATION_RELATIONMODE)
	    	{
	    		relationElement= new RelElement(beginX,beginY,tox+x-10,toy+y-10,ElementType.IMPLEMENTATION);
			    StringBuffer  panelStr= new StringBuffer(Constants.implementPanelAttr.trim());
			    relationElement.setPanelAttributes(panelStr);
	    	}
			else
			{
			relationElement= new RelElement(beginX,beginY,tox+x-10,toy+y-10,ElementType.SIMPLE_ASSOC);
			StringBuffer  panelStr= new StringBuffer(Constants.relationPanelAttr.trim());
			relationElement.setPanelAttributes(panelStr);
	    	 }
 			
			relationElement.setType(Constants.relationType);
			relationElement.setAdditionalAttributes(add_attr);
			// write co-ordinates again by Umlet logic
			//relationElement.reCalculateCoOrdinates();
			List<Element> elementList= DiagramManager.getUmlDiagram().getElements();
			elementList.add(relationElement);
			
		}
		
		if(drawMode==Constants.LOADELEMENT)
		{
			
			 
				String addAttr=relElement.getAdditionalAttributes().toString().trim();
			    String  coOrdinates[]=  addAttr.split(";");
			    x1Float= Float.parseFloat(coOrdinates[0]);
			    y1Float = Float.parseFloat(coOrdinates[1]);
			    x2Float = Float.parseFloat(coOrdinates[2]);
			    y2Float = Float.parseFloat(coOrdinates[3]);
			 
			    float fromX=relElement.getX();
				float fromY=relElement.getY();
				float toX;
				  float toY;
				// when loading from TouchMe
				/*if(fromX==x1Float && fromY==y1Float)
				{
					  toX=  x2Float;
					  toY = y2Float;
				}*/
				//else// when loading from Umlet
				{
					fromX=relElement.getX()+x1Float;
					fromY=relElement.getY()+y1Float;
					toX=  Math.abs((relElement.getX() + x2Float));
					toY =  Math.abs(relElement.getY() + y2Float);
					 
					 
				}
			 // start drawing line from origin point to end point of line
				if(type==Constants.IMPLEMENTATION_RELATIONMODE){
					Paint p3 = new Paint();
					p3.setAntiAlias(true);
				  DashPathEffect dashPath = new DashPathEffect(new float[] {20,5},1);
				  p3.setPathEffect(dashPath);
				  p3.setStrokeWidth(1);
				  p3.setStyle(Paint.Style.STROKE);
				  canvas.drawLine(fromX, fromY, toX, toY, p3);				  
				} 
				else
					canvas.drawLine(fromX, fromY, toX, toY, p);
			PointF arrowCoOrdinates[]=RelElement.calculateArrowCoOrdinates(fromX,fromY,toX,toY);
			ax[0] = (int) fromX;
			ax[1] = (int) fromX+ (int)arrowCoOrdinates[0].x;
			ax[2] = (int) fromX + (int)arrowCoOrdinates[1].x;
			ay[0] = (int) fromY;
			ay[1] = (int) fromY + (int)arrowCoOrdinates[0].y;
			ay[2] = (int) fromY + (int)arrowCoOrdinates[1].y;
			// now draw the polygon (triangle)
			
			p.setStyle(Style.FILL);
			p.setColor(Color.BLACK);
			p.setStyle(Style.STROKE);
			Path path= new Path();
		    path.moveTo(ax[0], ay[0]);
		    path.lineTo(ax[1], ay[1]);
		    path.lineTo(ax[2], ay[2]);
		    path.lineTo(ax[0], ay[0]);
		    if(type==Constants.INHERITANCE_RELATIONMODE || type== Constants.IMPLEMENTATION_RELATIONMODE)
		    {
		    canvas.drawPath(path, p);
		    }
			int delta= Constants.delta;
			// draw the move circles / also called as hotspots
		    p.setStyle(Style.STROKE);
		    p.setColor(Color.BLUE);
		    canvas.drawRect(fromX-delta, fromY-delta,fromX+delta,fromY+delta, p);
		    canvas.drawRect(toX-delta, toY-delta, toX+delta,toY+delta, p);
		    if(relElement.getType()==ElementType.SIMPLE_ASSOC)
		    {
		    	String panelAttr =relElement.getPanelAttributes().toString();
		    	
		    	StringBuffer token=new StringBuffer("");
				int fromIndex=0;
				int toIndex=0;
				
				//while(token.length()>0){
					toIndex=panelAttr.indexOf(";", fromIndex);				
				  token.append(panelAttr.subSequence(fromIndex, toIndex));
				  String str=StringEscapeUtils.unescapeHtml(token.toString());
				  drawSectionText(canvas,str, fromX+delta+4, fromY+4,p);
				  token.delete(0, token.length());
					fromIndex= toIndex+1;
					 token.append(panelAttr.subSequence(fromIndex, panelAttr.length()));
					 String str1=StringEscapeUtils.unescapeHtml(token.toString());
					  //drawSectionText(canvas,str1, fromX+delta+2, fromY+2,p2);
					 int lengt=str1.length();
					 drawSectionText(canvas,str1, toX-2*delta-3*lengt, toY-4,p);
	    						    		    	
		    }
		    	    		    	
		}
			    
	}
	
	
	
	public void drawClassDiagram(Canvas canvas,Element entity)
	{
		p.setColor(Color.BLACK);
		float x=entity.getX();
		float y=entity.getY();
		float h=entity.getH();
		float w=entity.getW();
		float textSpace=15;
		float lineSpace=7;
        Rect rect1 = new Rect();  
        rect1.left = (int) x;  
        rect1.top = (int) y;  
        rect1.bottom = (int) (y+h);  
        rect1.right = (int) (x+w);
        p2.setColor(Color.WHITE);         
        canvas.drawRect(rect1, p2);  
		mDrawable = new ShapeDrawable(new RectShape());
		mDrawable.getPaint().setColor(Color.BLACK);
		mDrawable.getPaint().setStyle(Style.STROKE);
		mDrawable.setBounds((int)entity.getX(), (int)entity.getY(),
				(int)(entity.getX() + entity.getW()),(int) (entity.getY()
						+ entity.getH()));
		
		mDrawable.draw(canvas);
		canvas=drawSection(canvas,p,entity.getPanelAttributes(),x,y,w,lineSpace,textSpace);
		Log.d(Constants.TAG,"Drawn class: ");
	}
	public Canvas drawSection(Canvas canvas, Paint paint, StringBuffer sb,float x, float y,float w,float lineSpace, float textSpace){
		StringBuffer token=new StringBuffer(" ");
		int fromIndex=0;
		int toIndex=0;
		boolean done=false;
		while(token.length()>0){
			toIndex=sb.indexOf("\n", fromIndex);
			token.delete(0, token.length());
			if(fromIndex>toIndex){
				token.append(sb.subSequence(fromIndex, sb.length()));
				done=true;
			}else 
				token.append(sb.subSequence(fromIndex, toIndex));
			fromIndex= toIndex+1;
			if(token.length()==2){
				y=y+lineSpace;
				canvas=drawSectionLine(canvas,x, y, w, paint);
			}
			else {
				if(token!=null){
					y=y+textSpace;
					if(token.charAt(0)=='*'){
						paint.setTypeface(Typeface.DEFAULT_BOLD);
						canvas=drawSectionText(canvas,token.substring(1,token.length()-1), x+10, y, paint);
						paint.setTypeface(Typeface.DEFAULT);
					}
					else if(token.charAt(0)=='/'){
						Typeface typeface=Typeface.create(Typeface.SERIF, Typeface.ITALIC);
						paint.setTypeface(typeface);
						canvas=drawSectionText(canvas,token.substring(1,token.length()-1), x+10, y, paint);
						paint.setTypeface(Typeface.DEFAULT);
					}
					else{
						String str=StringEscapeUtils.unescapeHtml(token.toString());
						canvas=drawSectionText(canvas,str, x+10, y, paint);
					}
				}
			}
			if(done)
				token.delete(0, token.length());
		}
		return canvas;
	}
	public Canvas drawSectionLine(Canvas canvas, float locX, float locY,float width,Paint paint){
		canvas.drawLine(locX, locY, locX+width, locY, paint);
		return canvas;
	}
	public Canvas drawSectionText(Canvas canvas,String text, float locX, float locY,Paint paint){		
		canvas.drawText(text,locX,locY, paint);
		return canvas;
	}
	
	public void drawUseCase(Canvas canvas,Element entity)
	{
		p2.setColor(Color.BLACK);		
		mDrawable = new ShapeDrawable(new OvalShape());
		mDrawable.getPaint().setStyle(Style.FILL);
		mDrawable.getPaint().setColor(Color.WHITE);
		mDrawable.setBounds((int)entity.getX(), (int)entity.getY(),
				(int)(entity.getX() + entity.getW()),(int) (entity.getY()
						+ entity.getH()));
		mDrawable.draw(canvas);
		String panelAttr =entity.getPanelAttributes().toString();
		drawSectionText(canvas,panelAttr, entity.getX() + 5, entity.getY()+25,p2);
	}
	private void drawActor(Canvas canvas,Element entity,int zoom_level){
		int x=(int)entity.getX();
		int y=(int)entity.getY();
		int width=(int) entity.getW();
		int height=(int) entity.getH();
		String text=entity.getPanelAttributes().toString();
		if((zoom_level<=0)||(zoom_level>20))
			zoom_level=10;
		float scale=0.4f*(zoom_level/10);
		int y0=y;
		int pad=2;
		width*=scale;
		height*=scale;
		
		int neck=(int)(15*scale);
		int head=(int)(15*scale);
		/*Paint paint = new Paint();
		paint.setColor(Color.LTGRAY);
		canvas.drawPaint(paint);
		paint.setAntiAlias(true);
		*/
		p.setStyle(Style.FILL);
		p.setColor(Color.WHITE);
		int w=width;
		Rect rect = new Rect();
		p.getTextBounds(text, 0, text.length(), rect);
		int x0=x-pad;
		int x2=x+w+pad;
		if(w<rect.right){
			w=(int) rect.right;
			int dif=(w-width)/2;
			x0=x-dif;
			x2=x0+w;
		}
		mDrawable = new ShapeDrawable(new RectShape());
		mDrawable.getPaint().setStyle(p.getStyle());
		mDrawable.getPaint().setColor(p.getColor());
		Rect bounds=new Rect(x0, y-head-pad, x2, y+height+10+rect.bottom);
		mDrawable.setBounds(bounds);
		mDrawable.draw(canvas);
		canvas.drawRect(bounds, p);
		x=x+(width/2);
		p.setStyle(Style.STROKE);
		p.setColor(Color.BLACK);
		canvas.drawCircle(x, y, head, p);
		y=y+(head);
		
		canvas.drawLine(x, y , x, y+neck, p);
		y=y+neck;
		canvas.drawLine(x-(width/2), y , x+(width/2), y, p);
		int y1=y+(2*neck);
		canvas.drawLine(x, y , x, y1, p);
		y=y1;
		y1=y0+height;
		float xleg=(width *3)/7;
		canvas.drawLine(x, y , x-xleg, y1, p);
		canvas.drawLine(x, y , x+xleg, y1, p);
		if(w==width)
			w=x-(width/2);
		else
			w=x-(w/2);
		canvas.drawText(text,w,y1+10, p);		
	}
}
